using System;
using System.Collections.Generic;
using System.Text;

namespace Common.Utilities.Persistence
{
    /// <summary>
    /// 
    /// </summary>
    public class EntityFieldMappingHelper
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static List<string> GetPropertyNames(object entity)
        {
            List<string> propNames = new List<string>();
            System.Reflection.PropertyInfo[] props = entity.GetType().GetProperties();
            if (props != null && props.Length > 0)
            {
                for (int i = 0; i < props.Length; i++)
                {
                    propNames.Add(props[i].Name);
                }
            }
            return propNames;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static List<NameType> GetFieldMappings(object entity)
        {
            List<NameType> fields = new List<NameType>();
            System.Reflection.PropertyInfo[] props = entity.GetType().GetProperties();
            if (props != null && props.Length > 0)
            {
                for (int i = 0; i < props.Length; i++)
                {
                    NameType field = new NameType();
                    field.Name = props[i].Name;
                    field.DbType = FieldDataType.ToDbType(props[i].PropertyType.ToString());
                    fields.Add(field);
                }
            }
            return fields;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static List<Tuple> GetSimpleFields(object entity)
        {
            List<Tuple> fields = new List<Tuple>();
            System.Reflection.PropertyInfo[] props = entity.GetType().GetProperties();
            if (props != null && props.Length > 0)
            {
                for (int i = 0; i < props.Length; i++)
                {
                    if (EntityFieldMappingHelper.GetFieldPropertyType(props[i]) == SerializablePropertyType.Simple)
                    {
                        Tuple field = new Tuple();
                        field.Name = props[i].Name;
                        field.DbType = FieldDataType.ToDbType(props[i].PropertyType.ToString());
                        object value = props[i].GetValue(entity, null);
                        field.Value = FieldValueConverter.ConvertToString(field.DbType, value);
                        fields.Add(field);
                    }
                }
            }
            return fields;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static List<IXmlSerializable> GetXmlSerializableCompositeFields(object entity)
        {
            List<IXmlSerializable> compositeFields = new List<IXmlSerializable>();
            System.Reflection.PropertyInfo[] props = entity.GetType().GetProperties();
            if (props != null && props.Length > 0)
            {
                for (int i = 0; i < props.Length; i++)
                {
                    if (EntityFieldMappingHelper.GetFieldPropertyType(props[i]) == SerializablePropertyType.CompositeXmlSerializable)
                    {
                        IXmlSerializable compositeField = props[i].GetValue(entity, null) as IXmlSerializable;
                        if (compositeField != null)
                        {
                            compositeFields.Add(compositeField);
                        }
                    }
                }
            }
            return compositeFields;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="propName"></param>
        /// <returns></returns>
        public static string GetPropertyValue(object entity, string propName)
        {
            string propValue = null;
            System.Reflection.PropertyInfo prop = EntityFieldMappingHelper.GetPropertyByName(entity, propName);
            if (prop != null)
            {
                object propValueObj = prop.GetValue(entity, null);
                propValue = FieldValueConverter.ConvertToString(FieldDataType.ToDbType(prop.PropertyType.ToString()), propValueObj);
            }
            return propValue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="propName"></param>
        /// <param name="propValue"></param>
        public static void SetPropertyValue(object entity, string propName, string propValue)
        {
            System.Reflection.PropertyInfo prop = EntityFieldMappingHelper.GetPropertyByName(entity, propName);
            if (prop != null)
            {
                object propValueObj = FieldValueConverter.ToValue(FieldDataType.ToDbType(prop.PropertyType.ToString()), propValue);
                prop.SetValue(entity, propValueObj, null);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static System.Reflection.PropertyInfo GetPropertyByName(object entity, string name)
        {
            System.Reflection.PropertyInfo prop = null;
            System.Reflection.PropertyInfo[] props = entity.GetType().GetProperties();
            if (props != null && props.Length > 0)
            {
                for (int i = 0; i < props.Length; i++)
                {
                    if (props[i].Name.ToLower() == name.ToLower())
                    {
                        prop = props[i];
                        break;
                    }
                }
            }
            return prop;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="prop"></param>
        /// <returns></returns>
        public static SerializablePropertyType GetFieldPropertyType(System.Reflection.PropertyInfo prop)
        {
            SerializablePropertyType propType = SerializablePropertyType.CompositeUnknown;

            List<Type> simpleTypes = new List<Type>();
            simpleTypes.Add(typeof(string));
            simpleTypes.Add(typeof(int));
            simpleTypes.Add(typeof(Int16));
            simpleTypes.Add(typeof(Int32));
            simpleTypes.Add(typeof(Int64));
            simpleTypes.Add(typeof(float));
            simpleTypes.Add(typeof(Single));
            simpleTypes.Add(typeof(double));
            simpleTypes.Add(typeof(bool));
            simpleTypes.Add(typeof(decimal));
            simpleTypes.Add(typeof(DateTime));
            simpleTypes.Add(typeof(Guid));
            simpleTypes.Add(typeof(byte));
            simpleTypes.Add(typeof(char));
            simpleTypes.Add(typeof(char[]));
            simpleTypes.Add(typeof(byte[]));
            simpleTypes.Add(typeof(System.Drawing.Image));
            simpleTypes.Add(typeof(System.Xml.XmlDocument));

            if (simpleTypes.Contains(prop.PropertyType))
            {
                propType = SerializablePropertyType.Simple;
            }
            else
            {
                Type[] interfaceTypes = prop.PropertyType.GetInterfaces();
                if (interfaceTypes != null)
                {
                    for (int i = 0; i < interfaceTypes.Length; i++)
                    {

                        if (interfaceTypes[i].IsInterface && interfaceTypes[i].IsGenericType)
                        {
                            propType = SerializablePropertyType.CompositeXmlSerializable;
                            break;
                        }
                    }
                }
            }

            return propType;
        }

    }
}
